home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / kernel / vm / ds5000.md / vm3max.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-12-19  |  61.8 KB  |  2,437 lines

  1. /* vmPmax.c -
  2.  *
  3.  *         This file contains all hardware dependent routines for the 3MAX.
  4.  *
  5.  * Copyright (C) 1989 Digital Equipment Corporation.
  6.  * Permission to use, copy, modify, and distribute this software and
  7.  * its documentation for any purpose and without fee is hereby granted,
  8.  * provided that the above copyright notice appears in all copies.  
  9.  * Digital Equipment Corporation makes no representations about the
  10.  * suitability of this software for any purpose.  It is provided "as is"
  11.  * without express or implied warranty.
  12.  */
  13.  
  14. #ifndef lint
  15. static char rcsid[] = "$Header: /cdrom/src/kernel/Cvsroot/kernel/vm/ds5000.md/vm3max.c,v 1.12 92/03/19 17:44:45 jhh Exp $ SPRITE (DECWRL)";
  16. #endif not lint
  17.  
  18. #include <sprite.h>
  19. #include <vm3maxConst.h>
  20. #include <vm.h>
  21. #include <vmInt.h>
  22. #include <vmMach.h>
  23. #include <vmMachInt.h>
  24. #include <list.h>
  25. #include <mach.h>
  26. #include <proc.h>
  27. #include <sched.h>
  28. #include <stdlib.h>
  29. #include <sync.h>
  30. #include <sys.h>
  31. #include <dbg.h>
  32. #include <bstring.h>
  33. #include <machMon.h>
  34.  
  35. #if (MACH_MAX_NUM_PROCESSORS == 1) /* uniprocessor implementation */
  36. #undef MASTER_LOCK
  37. #undef MASTER_UNLOCK
  38. #define MASTER_LOCK(x) DISABLE_INTR()
  39. #define MASTER_UNLOCK(x) ENABLE_INTR()
  40. #else
  41.  
  42. /*
  43.  * The master lock to synchronize access to the tlb.
  44.  */
  45. static Sync_Semaphore vmMachMutex;
  46. static Sync_Semaphore *vmMachMutexPtr = &vmMachMutex;
  47.  
  48. #endif
  49.  
  50. /*
  51.  * The environment variables on the memory bitmap:
  52.  */
  53. extern char mach_BitmapLen[];
  54. extern char mach_BitmapAddr[];
  55.  
  56. /*----------------------------------------------------------------------
  57.  * 
  58.  *             Hardware data structures
  59.  *
  60.  *
  61.  *----------------------------------------------------------------------
  62.  */
  63.  
  64. /*
  65.  * Machine dependent flags for the flags field in the Vm_VirtAddr struct.
  66.  * We are only allowed to use the second byte of the flags.
  67.  *
  68.  *    USING_MAPPED_SEG        The parsed virtual address falls into
  69.  *                    the mapping segment.
  70.  */
  71. #define    USING_MAPPED_SEG    0x100
  72.  
  73. /*
  74.  * The maximum amount of kernel heap available.  Sprite expects the
  75.  * sum of this value and the kernel start to be the kernel end.
  76.  * Since the MIPS machines have a big hole in the address space
  77.  * we have to add 1 Gig to cover the whole.
  78.  *
  79.  * Right now the amount is set to 1 Gig + 128 Meg
  80.  */
  81. int    vmMachKernMemSize = 0x40000000 + 0x8000000;
  82.  
  83. /*
  84.  * Table of info about each physical page on the machine.
  85.  */
  86. typedef struct PhysPage {
  87.     unsigned int    user:        1,
  88.             referenced: 1,
  89.             modified:   1;
  90. } PhysPage;
  91. PhysPage    *vmMachPhysPageArr;
  92.  
  93. /*
  94.  * Kernel mappings for all possible kernel memory.  Each entry contains
  95.  * the LOW tlb entry.
  96.  */
  97. unsigned int    *vmMach_KernelTLBMap;
  98.  
  99. /*
  100.  * PID allocation data structures.  We need a list of free and active
  101.  * PIDs as well as a mapping from segment to pid and back.
  102.  */
  103. typedef struct PIDListElem {
  104.     List_Links        links;
  105.     Proc_ControlBlock    *procPtr;
  106.     int            pid;
  107.     List_Links        tlbList;
  108. } PIDListElem;
  109. static PIDListElem    pidListElems[VMMACH_NUM_PIDS];
  110.  
  111. /*
  112.  * List of free pids.
  113.  */
  114. static List_Links    freePIDListHdr;
  115. static List_Links    *freePIDList = &freePIDListHdr;
  116.  
  117. /*
  118.  * List of active pids.
  119.  */
  120. static List_Links    activePIDListHdr;
  121. static List_Links    *activePIDList = &activePIDListHdr;
  122.  
  123. /*
  124.  * Amount of physical memory.
  125.  */
  126. int    vm_NumPhysPages;
  127.  
  128. extern    Address    vmMemEnd;
  129.  
  130. /*
  131.  * A TLB hash bucket.
  132.  */
  133. typedef struct TLBHashBucket {
  134.     List_Links        links;        /* Links so can be in PID chain. */
  135.     unsigned        low;        /* The TLB low register value. */
  136.     unsigned        high;        /* The TLB high register value. */
  137. } TLBHashBucket;
  138.  
  139. /*
  140.  * The TLB hash table.
  141.  */
  142. TLBHashBucket    vmMachTLBHashTable[VMMACH_NUM_TLB_HASH_ENTRIES];
  143.  
  144. /*
  145.  * Performance counters.  The number of fields cannot
  146.  */
  147. typedef struct {
  148.     int    savedAT;
  149.     int utlbFaultCount;
  150.     int utlbHitCount;
  151.     int modFaultCount;
  152.     int modHitCount;
  153.     int slowModCount;
  154.     int numInserts;
  155.     int numCollisions;
  156.     int numProbes;
  157.     int numFound;
  158. } TLBCounters;
  159. TLBCounters *tlbCountersPtr = (TLBCounters *)(0x80000000 + VMMACH_STAT_BASE_OFFSET);
  160.  
  161. /*
  162.  * Table of TLB entries for the user has kernel pages mapped into
  163.  * their address space.  There is only one such process (the X server).
  164.  */
  165. static unsigned    userMappingTable[VMMACH_USER_MAPPING_PAGES];
  166. static int            userMapIndex;
  167. static Boolean            userMapped = FALSE;
  168. static Proc_ControlBlock    *mappedProcPtr = (Proc_ControlBlock *)NIL;
  169.  
  170. /*
  171.  * Flag to allow the debugger to access IO space (below the heap.
  172.  */
  173.  
  174. Boolean vmAllowIOAccess = FALSE;
  175. /*
  176.  * Forward declarations.
  177.  */
  178. static int GetNumPages _ARGS_((void));
  179. static void PageInvalidate _ARGS_((register Vm_VirtAddr *virtAddrPtr,
  180.     unsigned int virtPage, Boolean segDeletion));
  181. INTERNAL static void TLBHashInsert _ARGS_((int pid, unsigned page,
  182.     unsigned lowReg, unsigned hiReg));
  183. INTERNAL static void TLBHashDelete _ARGS_((int pid, unsigned page));
  184. INTERNAL static void TLBHashFlushPID _ARGS_((int pid));
  185. INTERNAL static TLBHashBucket *TLBHashFind _ARGS_((int pid, unsigned page));
  186. static ReturnStatus VmMach_Alloc _ARGS_((VmMach_SharedData *sharedData,
  187.     int regionSize, Address *addr));
  188. static void VmMach_Unalloc _ARGS_((VmMach_SharedData *sharedData,
  189.     Address addr));
  190.  
  191.  
  192. /*
  193.  * ----------------------------------------------------------------------------
  194.  *
  195.  * VmMach_BootInit --
  196.  *
  197.  *      Do hardware dependent boot time initialization.
  198.  *
  199.  * Results:
  200.  *      None.
  201.  *
  202.  * Side effects:
  203.  *      Hardware page map for the kernel is initialized.  Also the various size
  204.  *     fields are filled in.
  205.  *
  206.  * ----------------------------------------------------------------------------
  207.  */
  208. void
  209. VmMach_BootInit(pageSizePtr, pageShiftPtr, pageTableIncPtr, kernMemSizePtr,
  210.         numKernPagesPtr, maxSegsPtr, maxProcessesPtr)
  211.     int    *pageSizePtr;
  212.     int    *pageShiftPtr;
  213.     int    *pageTableIncPtr;
  214.     int    *kernMemSizePtr;
  215.     int    *numKernPagesPtr;
  216.     int    *maxSegsPtr;
  217.     int *maxProcessesPtr;
  218. {
  219.     int            numPages;
  220.  
  221. #if (MACH_MAX_NUM_PROCESSORS > 1) /* uniprocessor implementation */
  222.     Sync_SemInitDynamic(&vmMachMutex, "Vm:vmMachMutex");
  223. #endif
  224.  
  225.     /*
  226.      * Do boot time allocation.
  227.      */
  228.     vm_NumPhysPages = GetNumPages();
  229.     vmMachPhysPageArr = 
  230.         (PhysPage *)Vm_BootAlloc(sizeof(PhysPage) * vm_NumPhysPages);
  231.     bzero((char *)vmMachPhysPageArr, sizeof(PhysPage) * vm_NumPhysPages);
  232.  
  233.     numPages = (unsigned) (mach_KernEnd - VMMACH_VIRT_CACHED_START) >> 
  234.                         VMMACH_PAGE_SHIFT;
  235.     vmMach_KernelTLBMap = (unsigned *)Vm_BootAlloc(sizeof(unsigned) * numPages);
  236.     bzero((char *)vmMach_KernelTLBMap, sizeof(unsigned) * numPages);
  237.  
  238.     /*
  239.      * Return lots of sizes to the machine independent module who called us.
  240.      */
  241.     *pageSizePtr = VMMACH_PAGE_SIZE;
  242.     *pageShiftPtr = VMMACH_PAGE_SHIFT;
  243.     *pageTableIncPtr = VMMACH_PAGE_TABLE_INCREMENT;
  244.     *kernMemSizePtr = vmMachKernMemSize;
  245.     *maxProcessesPtr = VMMACH_MAX_KERN_STACKS;
  246.     *numKernPagesPtr = vm_NumPhysPages;
  247.     *maxSegsPtr = -1;
  248. }
  249.  
  250.  
  251. /*
  252.  * ----------------------------------------------------------------------------
  253.  *
  254.  * GetNumPages --
  255.  *
  256.  *     Determine how many pages of physical memory there are.
  257.  *
  258.  * Results:
  259.  *     The number of physical pages.
  260.  *
  261.  * Side effects:
  262.  *     None.
  263.  *
  264.  * ----------------------------------------------------------------------------
  265.  */
  266. static int
  267. GetNumPages()
  268. {
  269.     int            i;
  270.     int            pages;
  271.     int            bitmapLen;
  272.     int            *bitmapAddr;
  273.     int            count = 0;
  274.  
  275.  
  276.     count = sscanf(mach_BitmapLen+2,"%x",&bitmapLen);
  277.     if (count != 1) {
  278.     panic("GetNumPages: unable to scan bitmap length.\n");
  279.     }
  280.     count = sscanf(mach_BitmapAddr+2,"%x",&bitmapAddr);
  281.     if (count != 1) {
  282.     panic("GetNumPages: unable to scan bitmap address.\n");
  283.     }
  284.     for (i=0;i<bitmapLen;i++) {
  285.     if (bitmapAddr[i] != 0xffffffff) break;
  286.     }
  287.     pages = i * 32;
  288.     for (;i<bitmapLen;i++) {
  289.     if (bitmapAddr[i] != 0x00000000) {
  290.         printf("Warning: Memory fragmentation at page 0x%x\n",i * 32);
  291.         break;
  292.     }
  293.     }
  294.     Mach_MonPrintf("%d pages of memory\n", pages);
  295.     return(pages); 
  296. }
  297.  
  298.  
  299. /*
  300.  * ----------------------------------------------------------------------------
  301.  *
  302.  * VmMach_AllocKernSpace --
  303.  *
  304.  *     Allocate memory for machine dependent stuff in the kernels VAS.
  305.  *
  306.  * Results:
  307.  *     None.
  308.  *
  309.  * Side effects:
  310.  *     None.
  311.  *
  312.  * ----------------------------------------------------------------------------
  313.  */
  314. Address
  315. VmMach_AllocKernSpace(baseAddr)
  316.     Address    baseAddr;
  317. {
  318.     return(baseAddr);
  319. }
  320.  
  321.  
  322. /*
  323.  * ----------------------------------------------------------------------------
  324.  *
  325.  * VmMach_Init --
  326.  *
  327.  *     Initialize all virtual memory data structures.
  328.  *
  329.  * Results:
  330.  *     None.
  331.  *
  332.  * Side effects:
  333.  *     All virtual memory linked lists and arrays are initialized.
  334.  *
  335.  * ----------------------------------------------------------------------------
  336.  */
  337. /*ARGSUSED*/
  338. void
  339. VmMach_Init(firstFreePage)
  340.     int    firstFreePage;    /* Virtual page that is the first free for the 
  341.              * kernel. */
  342. {
  343.     register    int         i;
  344.  
  345.     /*
  346.      * Initialize pid lists.  0 is invalid and PID 1 is for kernel processes.
  347.      */
  348.     List_Init(freePIDList);
  349.     List_Init(activePIDList);
  350.     for (i = 2; i < VMMACH_NUM_PIDS; i++) {
  351.     List_Insert((List_Links *)&pidListElems[i], 
  352.             LIST_ATREAR(freePIDList));
  353.     pidListElems[i].pid = i;
  354.     List_Init(&pidListElems[i].tlbList);
  355.     }
  356.  
  357.     /*
  358.      * Push vmMemEnd up to the beginning of dynamic memory.
  359.      */
  360.     vmMemEnd = (Address)VMMACH_VIRT_CACHED_START;
  361.     vm_SysSegPtr->numPages = VMMACH_VIRT_CACHED_START_PAGE - 
  362.                 vm_SysSegPtr->offset;
  363.  
  364.     /*
  365.      * Mark all entries in the TLB as invalid.  
  366.      */
  367.     VmMachFlushTLB();
  368.     for (i = 0; i < VMMACH_FIRST_RAND_ENTRY; i++) {
  369.     VmMachWriteIndexedTLB(i, 0, (unsigned)VMMACH_PHYS_CACHED_START_PAGE);
  370.     }
  371.     /*
  372.      * Zero out the TLB fault counters which are in low memory.
  373.      */
  374.     bzero((char *)tlbCountersPtr, sizeof(TLBCounters));
  375. }
  376.  
  377.  
  378. /*
  379.  * ----------------------------------------------------------------------------
  380.  *
  381.  * VmMach_SegInit --
  382.  *
  383.  *      Initialize hardware dependent data for a segment.
  384.  *
  385.  * Results:
  386.  *      None.
  387.  *
  388.  * Side effects:
  389.  *      Minimum and maximum address set in the segment table entry.
  390.  *
  391.  * ----------------------------------------------------------------------------
  392.  */
  393. void
  394. VmMach_SegInit(segPtr)
  395.     Vm_Segment    *segPtr;
  396. {
  397.     /*
  398.      * Set the minimum and maximum virtual addresses for this segment to
  399.      * be as small and as big as possible respectively because things will
  400.      * be prevented from growing automatically as soon as segments run into
  401.      * each other.
  402.      */
  403.     segPtr->minAddr = (Address)0;
  404.     segPtr->maxAddr = (Address)0x7fffffff;
  405. }
  406.  
  407.  
  408. /*
  409.  *----------------------------------------------------------------------
  410.  *
  411.  * VmMach_SegExpand --
  412.  *
  413.  *    Don't have to do anything.
  414.  *
  415.  * Results:
  416.  *    None.
  417.  *
  418.  * Side effects:
  419.  *    None.
  420.  *
  421.  *----------------------------------------------------------------------
  422.  */
  423. /*ARGSUSED*/
  424. void
  425. VmMach_SegExpand(segPtr, firstPage, lastPage)
  426.     Vm_Segment    *segPtr;    /* Segment to expand. */
  427.     int        firstPage;    /* First page to add. */
  428.     int        lastPage;    /* Last page to add. */
  429. {
  430. }
  431.  
  432.  
  433. /*
  434.  * ----------------------------------------------------------------------------
  435.  *
  436.  * VmMach_SegDelete --
  437.  *
  438.  *      Don't have to do anything.
  439.  *
  440.  * Results:
  441.  *      None.
  442.  *
  443.  * Side effects:
  444.  *      None.
  445.  *
  446.  * ----------------------------------------------------------------------------
  447.  */
  448. /*ARGSUSED*/
  449. void
  450. VmMach_SegDelete(segPtr)
  451.     Vm_Segment    *segPtr;    /* Pointer to segment to free. */
  452. {
  453. }
  454.  
  455.  
  456. /*
  457.  *----------------------------------------------------------------------
  458.  *
  459.  * VmMach_ProcInit --
  460.  *
  461.  *    Initalize the machine dependent part of the VM proc info.
  462.  *
  463.  * Results:
  464.  *    None.
  465.  *
  466.  * Side effects:
  467.  *    Machine dependent proc info is initialized.
  468.  *
  469.  *----------------------------------------------------------------------
  470.  */
  471. void
  472. VmMach_ProcInit(vmPtr)
  473.     register    Vm_ProcInfo    *vmPtr;
  474. {
  475.     if (vmPtr->machPtr == (VmMach_ProcData *)NIL) {
  476.     vmPtr->machPtr = (VmMach_ProcData *)malloc(sizeof(VmMach_ProcData));
  477.     }
  478.     vmPtr->machPtr->mapSegPtr = (struct Vm_Segment *)NIL;
  479.     vmPtr->machPtr->pid = VMMACH_INV_PID;
  480.     vmPtr->machPtr->sharedData.allocVector = (int *)NIL;
  481.     List_Init(&vmPtr->machPtr->kernSharedList);
  482. }
  483.  
  484.  
  485. /*
  486.  * ----------------------------------------------------------------------------
  487.  *
  488.  * VmMach_SetupContext --
  489.  *
  490.  *      Allocate a PID to the current process.
  491.  *    
  492.  * Results:
  493.  *      PID allocated.
  494.  *
  495.  * Side effects:
  496.  *      PID may be moved to end of active list and an entry may be taken off
  497.  *    of the free list.
  498.  *
  499.  * ----------------------------------------------------------------------------
  500.  */
  501. ENTRY ClientData
  502. VmMach_SetupContext(procPtr)
  503.     register    Proc_ControlBlock    *procPtr;
  504. {
  505.     VmMach_ProcData    *machPtr;
  506.     PIDListElem        *pidPtr;
  507.  
  508.     MASTER_LOCK(vmMachMutexPtr);
  509.  
  510.     machPtr = procPtr->vmPtr->machPtr;
  511.     if (procPtr->genFlags & (PROC_KERNEL | PROC_NO_VM)) {
  512.     /*
  513.      * This is a kernel process or a process that is exiting.  These
  514.      * processes use the kernel's pid.
  515.      */
  516.     machPtr->pid = VMMACH_KERN_PID;
  517.     VmMachSetPID(VMMACH_KERN_PID);
  518.     MASTER_UNLOCK(vmMachMutexPtr);
  519.     return((ClientData)machPtr->pid);
  520.     } 
  521.  
  522.     if (machPtr->pid == VMMACH_INV_PID) {
  523.     /*
  524.      * Allocate us a new PID.
  525.      */
  526.     if (List_IsEmpty(freePIDList)) {
  527.         vmStat.machDepStat.stealPID++;
  528.         pidPtr = (PIDListElem *)List_First(activePIDList);
  529.         pidPtr->procPtr->vmPtr->machPtr->pid = VMMACH_INV_PID;
  530.         VmMachFlushPIDFromTLB(pidPtr->pid);
  531.         TLBHashFlushPID(pidPtr->pid);
  532.     } else {
  533.         pidPtr = (PIDListElem *)List_First(freePIDList);
  534.     }
  535.     machPtr->pid = pidPtr->pid;
  536.     pidPtr->procPtr = procPtr;
  537.     } else {
  538.     pidPtr = &pidListElems[machPtr->pid];
  539.     }
  540.     /*
  541.      * Move the PID to the end of the PID list and set the hardware PID
  542.      * entry.
  543.      */
  544.     List_Move((List_Links *)pidPtr, LIST_ATREAR(activePIDList));
  545.     VmMachSetPID(machPtr->pid);
  546.  
  547.     MASTER_UNLOCK(vmMachMutexPtr);
  548.     return((ClientData)machPtr->pid);
  549. }
  550.  
  551.  
  552. /*
  553.  * ----------------------------------------------------------------------------
  554.  *
  555.  * Vm_FreeContext --
  556.  *
  557.  *      Release the PID for the current process and flush the TLB for this
  558.  *    PID.
  559.  *
  560.  * Results:
  561.  *      None.
  562.  *
  563.  * Side effects:
  564.  *      PID entry moved from active list to free list and TLB flushed for
  565.  *    the PID.
  566.  *
  567.  * ----------------------------------------------------------------------------
  568.  */
  569. ENTRY void
  570. VmMach_FreeContext(procPtr)
  571.     register    Proc_ControlBlock    *procPtr;
  572. {
  573.     PIDListElem        *pidPtr;
  574.     VmMach_ProcData    *machPtr;
  575.     List_Links        *elemPtr;
  576.     List_Links        *tmpPtr = (List_Links *) NIL;
  577.  
  578.     MASTER_LOCK(vmMachMutexPtr);
  579.  
  580.     machPtr = procPtr->vmPtr->machPtr;
  581.     if (machPtr->pid == VMMACH_INV_PID || machPtr->pid == VMMACH_KERN_PID) {
  582.     machPtr->pid = VMMACH_INV_PID;
  583.     MASTER_UNLOCK(vmMachMutexPtr);
  584.     return;
  585.     }
  586.     pidPtr = &pidListElems[machPtr->pid];
  587.     List_Move((List_Links *)pidPtr, LIST_ATREAR(freePIDList));
  588.     VmMachFlushPIDFromTLB(machPtr->pid);
  589.     TLBHashFlushPID(machPtr->pid);
  590.     machPtr->pid = VMMACH_INV_PID;
  591.     LIST_FORALL(&machPtr->kernSharedList, elemPtr) {
  592.     if (tmpPtr != (List_Links *) NIL) {
  593.         List_Remove(tmpPtr);
  594.         free((char *) tmpPtr);
  595.     }
  596.     tmpPtr = elemPtr;
  597.     }
  598.     if (tmpPtr != (List_Links *) NIL) {
  599.     List_Remove(tmpPtr);
  600.     free((char *) tmpPtr);
  601.     }
  602.     MASTER_UNLOCK(vmMachMutexPtr);
  603. }
  604.  
  605.  
  606. /*
  607.  * ----------------------------------------------------------------------------
  608.  *
  609.  * VmMach_ReinitContext --
  610.  *
  611.  *    Free the current PID and set up another one.  This is called by
  612.  *    routines such as Proc_Exec that add things to the context and
  613.  *    then have to abort or start a process running with a new image.
  614.  *
  615.  * Results:
  616.  *      None.
  617.  *
  618.  * Side effects:
  619.  *      The pid value in the machine dependent VM info for the process.
  620.  *
  621.  * ----------------------------------------------------------------------------
  622.  */
  623. void
  624. VmMach_ReinitContext(procPtr)
  625.     register    Proc_ControlBlock    *procPtr;
  626. {
  627.     VmMach_FreeContext(procPtr);
  628.     (void)VmMach_SetupContext(procPtr);
  629. }
  630.  
  631.  
  632. /*
  633.  *----------------------------------------------------------------------
  634.  *
  635.  * VmMach_VirtAddrParse --
  636.  *
  637.  *    See if the given address falls into the special mapping page.
  638.  *    If so parse it for our caller.
  639.  *
  640.  * Results:
  641.  *    TRUE if the address fell into the special mapping page, FALSE
  642.  *    otherwise.
  643.  *
  644.  * Side effects:
  645.  *    *transVirtAddrPtr may be filled in.
  646.  *
  647.  *----------------------------------------------------------------------
  648.  */
  649. Boolean
  650. VmMach_VirtAddrParse(procPtr, virtAddr, transVirtAddrPtr)
  651.     Proc_ControlBlock        *procPtr;
  652.     Address            virtAddr;
  653.     register    Vm_VirtAddr    *transVirtAddrPtr;
  654. {
  655.     VmMach_ProcData    *machPtr;
  656.  
  657.     if (virtAddr >= (Address)VMMACH_MAPPED_PAGE_ADDR) {
  658.     machPtr = procPtr->vmPtr->machPtr;
  659.     /*
  660.      * The address falls into the special mapping page.  Translate
  661.      * the address back to the segment that it falls into.
  662.      */
  663.     transVirtAddrPtr->segPtr = machPtr->mapSegPtr;
  664.     transVirtAddrPtr->page = machPtr->mappedPage;
  665.     transVirtAddrPtr->offset = (unsigned)virtAddr & VMMACH_OFFSET_MASK;
  666.     transVirtAddrPtr->flags = USING_MAPPED_SEG;
  667.     transVirtAddrPtr->sharedPtr = (Vm_SegProcList *) machPtr->sharedPtr;
  668.     return(TRUE);
  669.     } else {
  670.     return(FALSE);
  671.     }
  672. }
  673.  
  674.  
  675. /*
  676.  *----------------------------------------------------------------------
  677.  *
  678.  * VmMach_CopyInProc --
  679.  *
  680.  *    Copy from another processes address space into the current address
  681.  *    space.   This is done by mapping the other processes segment into
  682.  *    the current VAS and then doing the copy.  It assumed that this 
  683.  *    routine is called with the source process locked such that its
  684.  *    VM will not go away while we are doing this copy.
  685.  *
  686.  * Results:
  687.  *    SUCCESS if the copy succeeded, SYS_ARG_NOACCESS if fromAddr is invalid.
  688.  *
  689.  * Side effects:
  690.  *    What toAddr points to is modified.
  691.  *
  692.  *----------------------------------------------------------------------
  693.  */
  694. /*ARGSUSED*/
  695. ENTRY ReturnStatus
  696. VmMach_CopyInProc(numBytes, fromProcPtr, fromAddr, virtAddrPtr,
  697.               toAddr, toKernel)
  698.     int     numBytes;        /* The maximum number of bytes to 
  699.                        copy in. */
  700.     Proc_ControlBlock    *fromProcPtr;    /* Which process to copy from.*/
  701.     Address        fromAddr;    /* The address to copy from */
  702.     Vm_VirtAddr        *virtAddrPtr;
  703.     Address        toAddr;        /* The address to copy to */
  704.     Boolean        toKernel;    /* This copy is happening to the
  705.                      * kernel's address space. */
  706. {
  707.     ReturnStatus        status = SUCCESS;
  708.     register VmMach_ProcData    *machPtr;
  709.     Proc_ControlBlock        *toProcPtr;
  710.     int                pageOffset;
  711.     int                bytesToCopy;
  712.  
  713. /*
  714.     printf("VmMach_CopyInProc: num=%x from=%x toAddr=%x toK=%d\n",
  715.         numBytes, fromAddr, toAddr, toKernel);
  716.  */
  717.     toProcPtr = Proc_GetCurrentProc();
  718.     machPtr = toProcPtr->vmPtr->machPtr;
  719.     machPtr->mapSegPtr = virtAddrPtr->segPtr;
  720.     machPtr->sharedPtr = (Address) virtAddrPtr->sharedPtr;
  721.     machPtr->mappedPage = (unsigned int) (fromAddr) >> VMMACH_PAGE_SHIFT;
  722.     /*
  723.      * Do a page worths at a time.
  724.      */
  725.     while (numBytes > 0 && status == SUCCESS) {
  726.     pageOffset = (unsigned int)fromAddr & (VMMACH_PAGE_SIZE - 1);
  727.     bytesToCopy = VMMACH_PAGE_SIZE - pageOffset;
  728.     if (bytesToCopy > numBytes) {
  729.         bytesToCopy = numBytes;
  730.     }
  731.     /*
  732.      * Do the copy.
  733.      */
  734.     toProcPtr->vmPtr->vmFlags |= VM_COPY_IN_PROGRESS;
  735.     status = VmMachDoCopy(bytesToCopy,
  736.                   (Address)(VMMACH_MAPPED_PAGE_ADDR + pageOffset),
  737.                   toAddr);
  738.     toProcPtr->vmPtr->vmFlags &= ~VM_COPY_IN_PROGRESS;
  739.  
  740.     MASTER_LOCK(vmMachMutexPtr);
  741.     TLBHashDelete(machPtr->pid, (unsigned)VMMACH_MAPPED_PAGE_NUM);
  742.     VmMachFlushPageFromTLB(machPtr->pid, (unsigned)VMMACH_MAPPED_PAGE_NUM);
  743.     MASTER_UNLOCK(vmMachMutexPtr);
  744.  
  745.     if (status == SUCCESS) {
  746.         numBytes -= bytesToCopy;
  747.         fromAddr += bytesToCopy;
  748.         toAddr += bytesToCopy;
  749.     } else {
  750.         status = SYS_ARG_NOACCESS;
  751.     }
  752.     machPtr->mappedPage++;
  753.     }
  754.     machPtr->mapSegPtr = (struct Vm_Segment *)NIL;
  755.     return(status);
  756. }
  757.  
  758.  
  759. /*
  760.  *----------------------------------------------------------------------
  761.  *
  762.  * VmMach_CopyOutProc --
  763.  *
  764.  *    Copy from the current VAS to another processes VAS.  This is done by 
  765.  *    mapping the other processes segment into the current VAS and then 
  766.  *    doing the copy.  It assumed that this routine is called with the dest
  767.  *    process locked such that its VM will not go away while we are doing
  768.  *    the copy.
  769.  *
  770.  * Results:
  771.  *    SUCCESS if the copy succeeded, SYS_ARG_NOACCESS if fromAddr is invalid.
  772.  *
  773.  * Side effects:
  774.  *    What toAddr points to is modified.
  775.  *
  776.  *----------------------------------------------------------------------
  777.  */
  778. /*ARGSUSED*/
  779. ENTRY ReturnStatus
  780. VmMach_CopyOutProc(numBytes, fromAddr, fromKernel, toProcPtr, toAddr,
  781.            virtAddrPtr)
  782.     int         numBytes;    /* The maximum number of bytes to 
  783.                        copy in. */
  784.     Address        fromAddr;    /* The address to copy from */
  785.     Boolean        fromKernel;    /* This copy is happening to the
  786.                      * kernel's address space. */
  787.     Proc_ControlBlock    *toProcPtr;    /* Which process to copy from.*/
  788.     Address        toAddr;        /* The address to copy to */
  789.     Vm_VirtAddr        *virtAddrPtr;
  790. {
  791.     ReturnStatus        status = SUCCESS;
  792.     register VmMach_ProcData    *machPtr;
  793.     Proc_ControlBlock        *fromProcPtr;
  794.     int                pageOffset;
  795.     int                bytesToCopy;
  796.  
  797.  
  798. /*
  799.     printf("VmMach_CopyOutProc: num=%x from=%x fromK=%d toAddr=%x\n",
  800.         numBytes, fromAddr, fromKernel, toAddr);
  801.  */
  802.     fromProcPtr = Proc_GetCurrentProc();
  803.     machPtr = fromProcPtr->vmPtr->machPtr;
  804.     machPtr->mapSegPtr = virtAddrPtr->segPtr;
  805.     machPtr->mappedPage = (unsigned int) (toAddr) >> VMMACH_PAGE_SHIFT;
  806.     machPtr->sharedPtr = (Address) virtAddrPtr->sharedPtr;
  807.     /*
  808.      * Do a hardware segments worth at a time until done.
  809.      */
  810.     while (numBytes > 0 && status == SUCCESS) {
  811.     pageOffset = (unsigned)toAddr & (VMMACH_PAGE_SIZE - 1);
  812.     bytesToCopy = VMMACH_PAGE_SIZE - pageOffset;
  813.     if (bytesToCopy > numBytes) {
  814.         bytesToCopy = numBytes;
  815.     }
  816.     /*
  817.      * Do the copy.
  818.      */
  819.     fromProcPtr->vmPtr->vmFlags |= VM_COPY_IN_PROGRESS;
  820.     status = VmMachDoCopy(bytesToCopy, fromAddr,
  821.                   (Address) (VMMACH_MAPPED_PAGE_ADDR + pageOffset));
  822.     fromProcPtr->vmPtr->vmFlags &= ~VM_COPY_IN_PROGRESS;
  823.  
  824.     MASTER_LOCK(vmMachMutexPtr);
  825.     TLBHashDelete(machPtr->pid, (unsigned)VMMACH_MAPPED_PAGE_NUM);
  826.     VmMachFlushPageFromTLB(machPtr->pid, (unsigned)VMMACH_MAPPED_PAGE_NUM);
  827.     MASTER_UNLOCK(vmMachMutexPtr);
  828.  
  829.     if (status == SUCCESS) {
  830.         numBytes -= bytesToCopy;
  831.         fromAddr += bytesToCopy;
  832.         toAddr += bytesToCopy;
  833.     } else {
  834.         status = SYS_ARG_NOACCESS;
  835.     }
  836.  
  837.     machPtr->mappedPage++;
  838.     }
  839.     machPtr->mapSegPtr = (struct Vm_Segment *)NIL;
  840.     return(status);
  841. }
  842.  
  843.  
  844. /*
  845.  *----------------------------------------------------------------------
  846.  *
  847.  * VmMach_SetSegProt --
  848.  *
  849.  *    Change the protection in the page table for the given range of bytes
  850.  *    for the given segment.
  851.  *
  852.  * Results:
  853.  *    None.
  854.  *
  855.  * Side effects:
  856.  *    Page table may be modified for the segment.
  857.  *
  858.  *----------------------------------------------------------------------
  859.  */
  860. ENTRY void
  861. VmMach_SetSegProt(segPtr, firstPage, lastPage, makeWriteable)
  862.     register Vm_Segment        *segPtr;    /* Segment to change protection
  863.                            for. */
  864.     register int        firstPage;  /* First page to set protection
  865.                          * for. */
  866.     int                lastPage;   /* First page to set protection
  867.                          * for. */
  868.     Boolean            makeWriteable;/* TRUE => make the pages 
  869.                            *     writable.
  870.                            * FALSE => make readable only.*/
  871. {
  872.  
  873.     VmProcLink        *procLinkPtr;
  874.     int            i;
  875.     TLBHashBucket    *bucketPtr;
  876.  
  877.     MASTER_LOCK(vmMachMutexPtr);
  878.  
  879.     if (!makeWriteable || segPtr->type == VM_CODE) {
  880.     VmMachFlushTLB();
  881.     }
  882.  
  883.     LIST_FORALL(segPtr->procList, (List_Links *) procLinkPtr) {
  884.     for (i = firstPage; i <= lastPage; i++) {
  885.         bucketPtr= TLBHashFind(procLinkPtr->procPtr->vmPtr->machPtr->pid,
  886.                    (unsigned)i);
  887.         if (bucketPtr != (TLBHashBucket *)NIL) {
  888.         if (makeWriteable) {
  889.             bucketPtr->low |= VMMACH_TLB_ENTRY_WRITEABLE;
  890.         } else {
  891.             bucketPtr->low &= ~VMMACH_TLB_ENTRY_WRITEABLE;
  892.         }
  893. #ifdef notdef
  894.         if (segPtr->type == VM_CODE) {
  895.             bucketPtr->low |= VMMACH_TLB_NON_CACHEABLE_BIT;
  896.         }
  897. #endif
  898.         }
  899.     }
  900.     }
  901.  
  902.     MASTER_UNLOCK(vmMachMutexPtr);
  903. }
  904.  
  905.  
  906. /*
  907.  *----------------------------------------------------------------------
  908.  *
  909.  * VmMach_FlushCode --
  910.  *
  911.  *    Flush the specified address range from the instruction cache.
  912.  *
  913.  * Results:
  914.  *    None.
  915.  *
  916.  * Side effects:
  917.  *    Code is flushed from the cache.
  918.  *
  919.  *----------------------------------------------------------------------
  920.  */
  921. /*ARGSUSED*/
  922. void
  923. VmMach_FlushCode(procPtr, virtAddrPtr, physPage, numBytes)
  924.     Proc_ControlBlock    *procPtr;
  925.     Vm_VirtAddr        *virtAddrPtr;
  926.     unsigned        physPage;
  927.     int            numBytes;
  928. {
  929.     Mach_FlushCode((Address)((physPage << VMMACH_PAGE_SHIFT) +
  930.         virtAddrPtr->offset), (unsigned)numBytes);
  931. }
  932.  
  933.  
  934. /*
  935.  *----------------------------------------------------------------------
  936.  *
  937.  * VmMach_SetPageProt --
  938.  *
  939.  *    Set the protection in hardware and software for the given virtual
  940.  *    page.  
  941.  *
  942.  *    IMPORTANT: We assume that we have access to the list of processes
  943.  *           that are using this segment (i.e. the caller has the
  944.  *           virtual memory monitor lock down).
  945.  *
  946.  * Results:
  947.  *    None.
  948.  *
  949.  * Side effects:
  950.  *    Page table may be modified for the segment.
  951.  *
  952.  *----------------------------------------------------------------------
  953.  */
  954. ENTRY void
  955. VmMach_SetPageProt(virtAddrPtr, softPTE)
  956.     register    Vm_VirtAddr    *virtAddrPtr;    /* The virtual page to set the
  957.                          * protection for.*/
  958.     Vm_PTE            softPTE;    /* Software pte. */
  959. {
  960.     Vm_Segment        *segPtr;
  961.     VmProcLink        *procLinkPtr;
  962.     int            pid;
  963.     TLBHashBucket    *bucketPtr;
  964.  
  965.     MASTER_LOCK(vmMachMutexPtr);
  966.  
  967.     segPtr = virtAddrPtr->segPtr;
  968.     if (softPTE & (VM_COW_BIT | VM_READ_ONLY_PROT)) {
  969.     LIST_FORALL(segPtr->procList, (List_Links *) procLinkPtr) {
  970.         pid = procLinkPtr->procPtr->vmPtr->machPtr->pid;
  971.         (void) VmMachClearTLBModBit(pid, virtAddrPtr->page);
  972.         bucketPtr = TLBHashFind(pid, (unsigned)virtAddrPtr->page);
  973.         if (bucketPtr != (TLBHashBucket *)NIL) {
  974.         bucketPtr->low &= ~VMMACH_TLB_MOD_BIT;
  975.         }
  976.         bucketPtr = TLBHashFind(pid, (unsigned)virtAddrPtr->page);
  977.         if (bucketPtr != (TLBHashBucket *)NIL) {
  978.         bucketPtr->low &= ~VMMACH_TLB_ENTRY_WRITEABLE;
  979.         }
  980.     }
  981.     } else {
  982.     LIST_FORALL(segPtr->procList, (List_Links *) procLinkPtr) {
  983.         bucketPtr = TLBHashFind(procLinkPtr->procPtr->vmPtr->machPtr->pid,
  984.                     (unsigned)virtAddrPtr->page);
  985.         if (bucketPtr != (TLBHashBucket *)NIL) {
  986.         bucketPtr->low |= VMMACH_TLB_ENTRY_WRITEABLE;
  987.         }
  988.     }
  989.     }
  990.  
  991.     MASTER_UNLOCK(vmMachMutexPtr);
  992. }
  993.  
  994.  
  995. /*
  996.  * ----------------------------------------------------------------------------
  997.  *
  998.  * VmMach_AllocCheck --
  999.  *
  1000.  *      Determine if this page can be reallocated.  A page can be reallocated
  1001.  *    if it has not been referenced or modified.
  1002.  *  
  1003.  * Results:
  1004.  *      None.
  1005.  *
  1006.  * Side effects:
  1007.  *      The given page will be invalidated in the hardware if it has not
  1008.  *    been referenced and *refPtr and *modPtr will have the hardware 
  1009.  *    reference and modify bits or'd in.
  1010.  *
  1011.  * ----------------------------------------------------------------------------
  1012.  */
  1013. ENTRY void
  1014. VmMach_AllocCheck(virtAddrPtr, virtFrameNum, refPtr, modPtr)
  1015.     register    Vm_VirtAddr    *virtAddrPtr;
  1016.     unsigned    int        virtFrameNum;
  1017.     register    Boolean        *refPtr;
  1018.     register    Boolean        *modPtr;
  1019. {
  1020.     Boolean    origMod;
  1021.  
  1022.     MASTER_LOCK(vmMachMutexPtr);
  1023.  
  1024.     origMod = *modPtr;
  1025.  
  1026.     *refPtr |= vmMachPhysPageArr[virtFrameNum].referenced;
  1027.     *modPtr = vmMachPhysPageArr[virtFrameNum].modified;
  1028.     if (!*refPtr) {
  1029.     /*
  1030.      * Invalidate the page so that it will force a fault if it is
  1031.      * referenced.  Since our caller has blocked all faults on this
  1032.      * page, by invalidating it we can guarantee that the reference and
  1033.      * modify information that we are returning will be valid until
  1034.      * our caller reenables faults on this page.
  1035.      */
  1036.     PageInvalidate(virtAddrPtr, virtFrameNum, FALSE);
  1037.  
  1038.     if (origMod && !*modPtr) {
  1039.         /*
  1040.          * This page had the modify bit set in software but not in
  1041.          * hardware.
  1042.          */
  1043.         vmStat.notHardModPages++;
  1044.     }
  1045.     }
  1046.     *modPtr |= origMod;
  1047.  
  1048.     MASTER_UNLOCK(vmMachMutexPtr);
  1049. }
  1050.  
  1051.  
  1052. /*
  1053.  * ----------------------------------------------------------------------------
  1054.  *
  1055.  * VmMach_GetRefModBits --
  1056.  *
  1057.  *      Pull the reference and modified bits out of hardware.
  1058.  *  
  1059.  * Results:
  1060.  *      None.
  1061.  *
  1062.  * Side effects:
  1063.  *      
  1064.  *
  1065.  * ----------------------------------------------------------------------------
  1066.  */
  1067. /*ARGSUSED*/
  1068. ENTRY void
  1069. VmMach_GetRefModBits(virtAddrPtr, virtFrameNum, refPtr, modPtr)
  1070.     Vm_VirtAddr            *virtAddrPtr;
  1071.     unsigned    int        virtFrameNum;
  1072.     register    Boolean        *refPtr;
  1073.     register    Boolean        *modPtr;
  1074. {
  1075.     MASTER_LOCK(vmMachMutexPtr);
  1076.  
  1077.     *refPtr = vmMachPhysPageArr[virtFrameNum].referenced;
  1078.     *modPtr = vmMachPhysPageArr[virtFrameNum].modified;
  1079.  
  1080.     MASTER_UNLOCK(vmMachMutexPtr);
  1081. }
  1082.  
  1083.  
  1084. /*
  1085.  * ----------------------------------------------------------------------------
  1086.  *
  1087.  * VmMach_ClearRefBit --
  1088.  *
  1089.  *      Clear the reference bit at the given virtual address.
  1090.  *
  1091.  * Results:
  1092.  *      None.
  1093.  *
  1094.  * Side effects:
  1095.  *      Hardware reference bit cleared.
  1096.  *
  1097.  * ----------------------------------------------------------------------------
  1098.  */
  1099. /*ARGSUSED*/
  1100. ENTRY void
  1101. VmMach_ClearRefBit(virtAddrPtr, virtFrameNum)
  1102.     Vm_VirtAddr        *virtAddrPtr;
  1103.     unsigned     int    virtFrameNum;
  1104. {
  1105.     MASTER_LOCK(vmMachMutexPtr);
  1106.  
  1107.     vmMachPhysPageArr[virtFrameNum].referenced = 0;
  1108.  
  1109.     MASTER_UNLOCK(vmMachMutexPtr);
  1110. }
  1111.  
  1112.  
  1113. /*
  1114.  * ----------------------------------------------------------------------------
  1115.  *
  1116.  * VmMach_ClearModBit --
  1117.  *
  1118.  *      Clear the modified bit at the given virtual address.
  1119.  *
  1120.  * Results:
  1121.  *      None.
  1122.  *
  1123.  * Side effects:
  1124.  *      Hardware modified bit cleared.
  1125.  *
  1126.  * ----------------------------------------------------------------------------
  1127.  */
  1128. ENTRY void
  1129. VmMach_ClearModBit(virtAddrPtr, virtFrameNum)
  1130.     register    Vm_VirtAddr    *virtAddrPtr;
  1131.     unsigned    int        virtFrameNum;
  1132. {
  1133.     register    Vm_Segment    *segPtr;
  1134.     VmProcLink            *procLinkPtr;
  1135.     int                pid;
  1136.     TLBHashBucket        *hashBucketPtr;
  1137.  
  1138.     MASTER_LOCK(vmMachMutexPtr);
  1139.  
  1140.     vmMachPhysPageArr[virtFrameNum].modified = 0;
  1141.  
  1142.     segPtr = virtAddrPtr->segPtr;
  1143.     LIST_FORALL(segPtr->procList, (List_Links *) procLinkPtr) {
  1144.     pid = procLinkPtr->procPtr->vmPtr->machPtr->pid;
  1145.     (void) VmMachClearTLBModBit(pid, virtAddrPtr->page);
  1146.     hashBucketPtr = TLBHashFind(pid, (unsigned)virtAddrPtr->page);
  1147.     if (hashBucketPtr != (TLBHashBucket *)NIL) {
  1148.         hashBucketPtr->low &= ~VMMACH_TLB_MOD_BIT;
  1149.     }
  1150.     }
  1151.  
  1152.     MASTER_UNLOCK(vmMachMutexPtr);
  1153. }
  1154.  
  1155.  
  1156. /*
  1157.  * ----------------------------------------------------------------------------
  1158.  *
  1159.  * VmMach_PageValidate --
  1160.  *
  1161.  *      Validate a page for the given virtual address.  It is assumed that when
  1162.  *      this routine is called that the pid register contains the pid in which
  1163.  *    this page will be validated.
  1164.  *
  1165.  * Results:
  1166.  *      None.
  1167.  *
  1168.  * Side effects:
  1169.  *      The page table and hardware segment tables associated with the segment
  1170.  *      are modified to validate the page.
  1171.  *
  1172.  * ----------------------------------------------------------------------------
  1173.  */
  1174. ENTRY void
  1175. VmMach_PageValidate(virtAddrPtr, pte) 
  1176.     register    Vm_VirtAddr    *virtAddrPtr;
  1177.     Vm_PTE            pte;
  1178. {
  1179.     Proc_ControlBlock    *procPtr;
  1180.     VmMach_ProcData    *machPtr;
  1181.     unsigned        lowEntry;
  1182.     unsigned        virtPage;
  1183.     int            retVal;
  1184.     int            page;
  1185.  
  1186.     MASTER_LOCK(vmMachMutexPtr);
  1187.  
  1188.     procPtr = Proc_GetCurrentProc();
  1189.     machPtr = procPtr->vmPtr->machPtr;
  1190.     if (machPtr->pid == 0) {
  1191.     VmMach_ReinitContext(procPtr);
  1192.     }
  1193.  
  1194.     /*
  1195.      * Set up the TLB entry and the physical page info.
  1196.      */
  1197.     if (virtAddrPtr->segPtr == vm_SysSegPtr) {
  1198.     lowEntry = ((pte & VM_PAGE_FRAME_FIELD) << VMMACH_TLB_PHYS_PAGE_SHIFT)| 
  1199.             VMMACH_TLB_VALID_BIT | VMMACH_TLB_GLOBAL_BIT | 
  1200.             VMMACH_TLB_MOD_BIT;
  1201.     retVal = VmMachWriteTLB(lowEntry,
  1202.           (unsigned) ((virtAddrPtr->page << VMMACH_TLB_VIRT_PAGE_SHIFT) | 
  1203.                (VMMACH_KERN_PID << VMMACH_TLB_PID_SHIFT)));
  1204.     if (retVal >= 0) {
  1205.         panic("VmMach_PageValidate: Kern TLB entry found\n");
  1206.     }
  1207.     page = virtAddrPtr->page - VMMACH_VIRT_CACHED_START_PAGE;
  1208.     if (page >= 0) {
  1209.         vmMach_KernelTLBMap[page] = lowEntry;
  1210.     }
  1211.     } else {
  1212.     unsigned    highEntry;
  1213.     Boolean        shared = FALSE;
  1214.     VmMach_KernSharedInfo    *infoPtr = (VmMach_KernSharedInfo *) NIL
  1215.     ;
  1216.  
  1217.     if (!List_IsEmpty(&machPtr->kernSharedList)) {
  1218.         LIST_FORALL(&machPtr->kernSharedList, (List_Links *) infoPtr) {
  1219.         if ((virtAddrPtr->page >= infoPtr->firstPage) &&
  1220.             (virtAddrPtr->page <= infoPtr->lastPage)) {
  1221.             shared = TRUE;
  1222.             List_Move((List_Links *) infoPtr, 
  1223.             LIST_ATFRONT(&machPtr->kernSharedList));
  1224.         }
  1225.         }
  1226.     }
  1227.     if ((pte & VM_PAGE_FRAME_FIELD) < vm_NumPhysPages) {
  1228.         vmMachPhysPageArr[pte & VM_PAGE_FRAME_FIELD].user = 1;
  1229.     }
  1230.     lowEntry = ((pte & VM_PAGE_FRAME_FIELD) << 
  1231.                 VMMACH_TLB_PHYS_PAGE_SHIFT) | 
  1232.             VMMACH_TLB_VALID_BIT;
  1233.     if (!(pte & (VM_COW_BIT | VM_READ_ONLY_PROT)) && !(virtAddrPtr->flags
  1234.         & VM_READONLY_SEG)) {
  1235.         lowEntry |= VMMACH_TLB_ENTRY_WRITEABLE;
  1236.     }
  1237.     if (shared) {
  1238.         lowEntry |= VMMACH_TLB_MOD_BIT;
  1239.         if (infoPtr->flags & VMMACH_KERN_SHARED_UNCACHEABLE) {
  1240.         lowEntry |= VMMACH_TLB_NON_CACHEABLE_BIT;
  1241.         }
  1242.     }
  1243.     if (virtAddrPtr->flags & USING_MAPPED_SEG) {
  1244.         virtPage = VMMACH_MAPPED_PAGE_NUM;
  1245.     } else {
  1246.         virtPage = virtAddrPtr->page;
  1247.     }
  1248.     if (machPtr->modPage == virtPage) {
  1249.         /*
  1250.          * We are validating after a TLB modified fault so set the modify
  1251.          * bit.
  1252.          */
  1253.         lowEntry |= VMMACH_TLB_MOD_BIT;
  1254.         vmMachPhysPageArr[pte & VM_PAGE_FRAME_FIELD].modified = 1;
  1255.     }
  1256.  
  1257.     highEntry = (virtPage << VMMACH_TLB_VIRT_PAGE_SHIFT) |
  1258.             (machPtr->pid << VMMACH_TLB_PID_SHIFT);
  1259.     TLBHashInsert(machPtr->pid, virtPage, lowEntry, highEntry);
  1260.     retVal = VmMachWriteTLB(lowEntry, highEntry);
  1261.     if (retVal >= 0 && !(machPtr->modPage == virtPage)) {
  1262.         panic("VmMach_PageValidate: Non-modified user TLB entry found\n");
  1263.     }
  1264.     }
  1265.  
  1266.     MASTER_UNLOCK(vmMachMutexPtr);
  1267. }
  1268.  
  1269.  
  1270. /*
  1271.  * ----------------------------------------------------------------------------
  1272.  *
  1273.  * PageInvalidate --
  1274.  *
  1275.  *      Invalidate a page for the given segment.  
  1276.  *
  1277.  * Results:
  1278.  *      None.
  1279.  *
  1280.  * Side effects:
  1281.  *      The page table and hardware tables associated with the segment
  1282.  *      are modified to invalidate the page.
  1283.  *
  1284.  * ----------------------------------------------------------------------------
  1285.  */
  1286. /*ARGSUSED*/
  1287. INTERNAL static void
  1288. PageInvalidate(virtAddrPtr, virtPage, segDeletion) 
  1289.     register    Vm_VirtAddr    *virtAddrPtr;
  1290.     unsigned     int        virtPage;
  1291.     Boolean            segDeletion;
  1292. {
  1293.     PhysPage        *physPagePtr;
  1294.  
  1295.     physPagePtr = &vmMachPhysPageArr[virtPage];
  1296.     if ((physPagePtr->user && virtAddrPtr->segPtr != vm_SysSegPtr) ||
  1297.         !physPagePtr->user) {
  1298.     /*
  1299.      * Clear out reference and modified info for this page.  We can
  1300.      * only clear it if one of two conditions hold:
  1301.      *
  1302.      *    1) It has been validated in a user's address space and
  1303.      *       is now being invalidated from a user's address space.
  1304.      *    2) It has never been validated in a user's address space.
  1305.      *
  1306.      * We have to make this distinction because a page can be mapped
  1307.      * both by a user and the kernel at the same time and we need to
  1308.      * make sure that the kernel invalidation doesn't wipe out good
  1309.      * user reference and modify information.
  1310.      */
  1311.     physPagePtr->user = 0;
  1312.     physPagePtr->referenced = 0;
  1313.     physPagePtr->modified = 0;
  1314.     }
  1315.  
  1316.     if (virtAddrPtr->segPtr == vm_SysSegPtr) {
  1317.     int    page;
  1318.  
  1319.     page = virtAddrPtr->page - VMMACH_VIRT_CACHED_START_PAGE;
  1320.     if (page >= 0) {
  1321.         vmMach_KernelTLBMap[page] = 0;
  1322.     }
  1323.     (void) VmMachFlushPageFromTLB(VMMACH_KERN_PID, 
  1324.                       (unsigned)virtAddrPtr->page);
  1325.     } else {
  1326.     VmProcLink    *procLinkPtr;
  1327.     int        pid;
  1328.  
  1329.     /*
  1330.      * Flush the page from all pids.
  1331.      */
  1332.     LIST_FORALL(virtAddrPtr->segPtr->procList, (List_Links *) procLinkPtr) {
  1333.         pid = procLinkPtr->procPtr->vmPtr->machPtr->pid;
  1334.         (void) VmMachFlushPageFromTLB(pid, (unsigned)virtAddrPtr->page);
  1335.         TLBHashDelete(pid, (unsigned)virtAddrPtr->page);
  1336.     }
  1337.     if (virtAddrPtr->segPtr->type == VM_CODE) {
  1338.         /*
  1339.          * If a code page flush it from the instruction cache.
  1340.          */
  1341.         Mach_FlushCode((Address)(virtPage << VMMACH_PAGE_SHIFT),
  1342.             VMMACH_PAGE_SIZE);
  1343.     }
  1344.     }
  1345. }
  1346.  
  1347.  
  1348. /*
  1349.  * ----------------------------------------------------------------------------
  1350.  *
  1351.  * VmMach_PageInvalidate --
  1352.  *
  1353.  *      Invalidate a page for the given segment.  
  1354.  *
  1355.  * Results:
  1356.  *      None.
  1357.  *
  1358.  * Side effects:
  1359.  *      The page table and hardware segment tables associated with the segment
  1360.  *      are modified to invalidate the page.
  1361.  *
  1362.  * ----------------------------------------------------------------------------
  1363.  */
  1364. ENTRY void
  1365. VmMach_PageInvalidate(virtAddrPtr, virtPage, segDeletion) 
  1366.     register    Vm_VirtAddr    *virtAddrPtr;
  1367.     unsigned     int        virtPage;
  1368.     Boolean            segDeletion;
  1369. {
  1370.     MASTER_LOCK(vmMachMutexPtr);
  1371.  
  1372.     PageInvalidate(virtAddrPtr, virtPage, segDeletion);
  1373.  
  1374.     MASTER_UNLOCK(vmMachMutexPtr);
  1375. }
  1376.  
  1377.  
  1378. /*
  1379.  *----------------------------------------------------------------------
  1380.  *
  1381.  * VmMach_PinUserPages --
  1382.  *
  1383.  *    Force a user page to be resident in memory.
  1384.  *
  1385.  * Results:
  1386.  *    None.
  1387.  *
  1388.  * Side effects:
  1389.  *    None.
  1390.  *
  1391.  *----------------------------------------------------------------------
  1392.  */
  1393. /*ARGSUSED*/
  1394. void
  1395. VmMach_PinUserPages(mapType, virtAddrPtr, lastPage)
  1396.     int        mapType;
  1397.     Vm_VirtAddr    *virtAddrPtr;
  1398.     int        lastPage;
  1399. {
  1400. }
  1401.  
  1402.  
  1403. /*
  1404.  *----------------------------------------------------------------------
  1405.  *
  1406.  * VmMach_UnpinUserPages --
  1407.  *
  1408.  *    Allow a page that was pinned to be unpinned.
  1409.  *
  1410.  * Results:
  1411.  *    None.
  1412.  *
  1413.  * Side effects:
  1414.  *    None.
  1415.  *
  1416.  *----------------------------------------------------------------------
  1417.  */
  1418. /*ARGSUSED*/
  1419. ENTRY void
  1420. VmMach_UnpinUserPages(virtAddrPtr, lastPage)
  1421.     Vm_VirtAddr    *virtAddrPtr;
  1422.     int        lastPage;
  1423. {
  1424. }
  1425.  
  1426.  
  1427. /*
  1428.  *----------------------------------------------------------------------
  1429.  *
  1430.  * VmMach_FlushPage --
  1431.  *
  1432.  *    Flush the page at the given virtual address from all caches.  We
  1433.  *    don't have to do anything on the Sun-2 and Sun-3 workstations
  1434.  *    that we have.
  1435.  *
  1436.  * Results:
  1437.  *    None.
  1438.  *
  1439.  * Side effects:
  1440.  *    The given page is flushed from the caches.
  1441.  *
  1442.  *----------------------------------------------------------------------
  1443.  */
  1444. /*ARGSUSED*/
  1445. void
  1446. VmMach_FlushPage(virtAddrPtr, invalidate)
  1447.     Vm_VirtAddr    *virtAddrPtr;
  1448.     Boolean    invalidate;    /* Should invalidate the pte after flushing. */
  1449. {
  1450. }
  1451.  
  1452.  
  1453. /*
  1454.  *----------------------------------------------------------------------
  1455.  *
  1456.  * VmMach_HandleSegMigration --
  1457.  *
  1458.  *    Handle machine-dependent aspects of segment preparation for migration.
  1459.  *    There's nothing to do on this machine.
  1460.  *
  1461.  * Results:
  1462.  *    None.
  1463.  *
  1464.  * Side effects:
  1465.  *    None.
  1466.  *
  1467.  *----------------------------------------------------------------------
  1468.  */
  1469. /*ARGSUSED*/
  1470. void
  1471. VmMach_HandleSegMigration(segPtr)
  1472.     Vm_Segment    *segPtr;
  1473. {
  1474.     return;
  1475. }
  1476.  
  1477.  
  1478.  
  1479. /*
  1480.  *----------------------------------------------------------------------
  1481.  *
  1482.  * VmMach_Cmd --
  1483.  *
  1484.  *    Machine dependent vm commands.
  1485.  *
  1486.  * Results:
  1487.  *    None.
  1488.  *
  1489.  * Side effects:
  1490.  *    None.
  1491.  *
  1492.  *----------------------------------------------------------------------
  1493.  */
  1494. /*ARGSUSED*/
  1495. ReturnStatus
  1496. VmMach_Cmd(command, arg)
  1497.     int    command;
  1498.     int arg;
  1499. {
  1500.     return(GEN_INVALID_ARG);
  1501. }
  1502.  
  1503.  
  1504.  
  1505. /*
  1506.  *----------------------------------------------------------------------
  1507.  *
  1508.  * VmMach_TLBFault --
  1509.  *
  1510.  *    Handle a TLB fault.
  1511.  *
  1512.  * Results:
  1513.  *    None.
  1514.  *
  1515.  * Side effects:
  1516.  *    None.
  1517.  *
  1518.  *----------------------------------------------------------------------
  1519.  */
  1520. ENTRY ReturnStatus
  1521. VmMach_TLBFault(virtAddr)
  1522.     Address    virtAddr;
  1523. {
  1524.  
  1525.     if (virtAddr >= (Address)VMMACH_VIRT_CACHED_START &&
  1526.         virtAddr < (Address)VMMACH_MAPPED_PAGE_ADDR) {
  1527.     dprintf("fault 1\n");
  1528.     return(FAILURE);
  1529.     } else if (virtAddr >= (Address)VMMACH_USER_MAPPING_BASE_ADDR &&
  1530.            virtAddr < (Address)VMMACH_PHYS_CACHED_START) {
  1531.     /*
  1532.      * This address falls into the range of address that are used to
  1533.      * map kernel pages into a user's address space.
  1534.      */
  1535.     unsigned         virtPage, lowEntry, highEntry;
  1536.     int             pid;
  1537.     VmMach_ProcData        *machPtr;
  1538.     Proc_ControlBlock    *procPtr;
  1539.     Boolean            found = FALSE;
  1540.     VmMach_KernSharedInfo    *infoPtr;
  1541.  
  1542.     procPtr = Proc_GetCurrentProc();
  1543.     machPtr = procPtr->vmPtr->machPtr;
  1544.     pid = procPtr->vmPtr->machPtr->pid;
  1545.     virtPage = (unsigned)virtAddr >> VMMACH_PAGE_SHIFT;
  1546.     LIST_FORALL(&machPtr->kernSharedList, (List_Links *) infoPtr) {
  1547.         if ((virtPage >= infoPtr->firstPage) &&
  1548.         (virtPage <= infoPtr->lastPage)) {
  1549.         found = TRUE;
  1550.         List_Move((List_Links *) infoPtr, 
  1551.             LIST_ATFRONT(&machPtr->kernSharedList));
  1552.         break;
  1553.         }
  1554.     }
  1555.     if (!found) {
  1556.         return FAILURE;
  1557.     }
  1558.     lowEntry = (virtPage - infoPtr->firstPage + infoPtr->firstPhysPage) <<
  1559.             VMMACH_TLB_PHYS_PAGE_SHIFT;
  1560.     lowEntry |= VMMACH_TLB_VALID_BIT | VMMACH_TLB_MOD_BIT;
  1561.     if (infoPtr->flags & VMMACH_KERN_SHARED_UNCACHEABLE) {
  1562.         lowEntry |= VMMACH_TLB_NON_CACHEABLE_BIT;
  1563.     }
  1564.     highEntry = (virtPage << VMMACH_TLB_VIRT_PAGE_SHIFT) |
  1565.             (pid << VMMACH_TLB_PID_SHIFT);
  1566.  
  1567.     MASTER_LOCK(vmMachMutexPtr);
  1568.     TLBHashInsert(pid, virtPage, lowEntry, highEntry);
  1569.     (void)VmMachWriteTLB(lowEntry, highEntry);
  1570.     MASTER_UNLOCK(vmMachMutexPtr);
  1571.  
  1572.     return(SUCCESS);
  1573.     } else {
  1574.     ReturnStatus status;
  1575.     status = Vm_PageIn(virtAddr, FALSE);
  1576.     if (status != SUCCESS) {
  1577.         dprintf("fault 4\n");
  1578.     }
  1579.     return status;
  1580.     /*
  1581.     return(Vm_PageIn(virtAddr, FALSE));
  1582.     */
  1583.     }
  1584. }
  1585.  
  1586.  
  1587. /*
  1588.  *----------------------------------------------------------------------
  1589.  *
  1590.  * VmMach_TLBModFault --
  1591.  *
  1592.  *    Handle a TLB modify fault.
  1593.  *
  1594.  * Results:
  1595.  *    None.
  1596.  *
  1597.  * Side effects:
  1598.  *    None.
  1599.  *
  1600.  *----------------------------------------------------------------------
  1601.  */
  1602. ReturnStatus
  1603. VmMach_TLBModFault(virtAddr)
  1604.     Address    virtAddr;
  1605. {
  1606.     Proc_ControlBlock        *procPtr;
  1607.     ReturnStatus        status;
  1608.  
  1609.     if (virtAddr >= (Address)VMMACH_VIRT_CACHED_START &&
  1610.     virtAddr < (Address)VMMACH_MAPPED_PAGE_ADDR) {
  1611.     /*
  1612.      * We shouldn't get TLB modified faults for kernel virtual
  1613.      * addresses because the modify bit was set when we validated the 
  1614.      * page.
  1615.      */
  1616.     panic("VmMach_TLBModFault: Kernel TLB mod fault\n");
  1617.     return(FAILURE);
  1618.     }
  1619.     tlbCountersPtr->slowModCount++;
  1620.     procPtr = Proc_GetCurrentProc();
  1621.     procPtr->vmPtr->machPtr->modPage = (unsigned)virtAddr >> VMMACH_PAGE_SHIFT;
  1622.     status = Vm_PageIn(virtAddr, TRUE);
  1623.     procPtr->vmPtr->machPtr->modPage = 0;
  1624.     return(status);
  1625. }
  1626.  
  1627.  
  1628. /*
  1629.  *----------------------------------------------------------------------
  1630.  *
  1631.  * VmMach_MapKernelIntoUser --
  1632.  *
  1633.  *    Unimplemented on PMAX.
  1634.  *
  1635.  * Results:
  1636.  *    FAILURE.
  1637.  *
  1638.  * Side effects:
  1639.  *    None.
  1640.  *
  1641.  *----------------------------------------------------------------------
  1642.  */
  1643. ReturnStatus
  1644. VmMach_MapKernelIntoUser()
  1645. {
  1646.     return(FAILURE);
  1647. }
  1648.  
  1649.  
  1650. /*
  1651.  *----------------------------------------------------------------------
  1652.  *
  1653.  * VmMach_Trace --
  1654.  *
  1655.  *    Virtual memory tracing.
  1656.  *
  1657.  * Results:
  1658.  *    None.
  1659.  *
  1660.  * Side effects:
  1661.  *    None.
  1662.  *
  1663.  *----------------------------------------------------------------------
  1664.  */
  1665. void
  1666. VmMach_Trace()
  1667. {
  1668. }
  1669.  
  1670.  
  1671. /*
  1672.  *----------------------------------------------------------------------
  1673.  *
  1674.  * VmMach_MakeDebugAccessible --
  1675.  *
  1676.  *    Make the given address accessible for the debugger.
  1677.  *
  1678.  * Results:
  1679.  *    TRUE if could make accessible, FALSE if couldn't.
  1680.  *
  1681.  * Side effects:
  1682.  *    None.
  1683.  *
  1684.  *----------------------------------------------------------------------
  1685.  */
  1686. Boolean
  1687. VmMach_MakeDebugAccessible(addr)
  1688.     unsigned    addr;
  1689. {
  1690.     unsigned virtPage, lowEntry, highEntry;
  1691.  
  1692.     if (addr < (unsigned)VMMACH_VIRT_CACHED_START) {
  1693.     if (addr < (unsigned)VMMACH_PHYS_UNCACHED_START) {
  1694.         if ((addr < (unsigned)VMMACH_PHYS_CACHED_START + 
  1695.             vm_NumPhysPages * VMMACH_PAGE_SIZE) &&
  1696.         (addr >= (unsigned)VMMACH_PHYS_CACHED_START)) {
  1697.         return TRUE;
  1698.         }
  1699.     } else {
  1700.         if (addr < (unsigned)VMMACH_PHYS_UNCACHED_START + 
  1701.             vm_NumPhysPages * VMMACH_PAGE_SIZE) {
  1702.         return TRUE;
  1703.         } else if (vmAllowIOAccess) {
  1704.         if ((addr < (unsigned) MACH_IO_SLOT_ADDR(7)) &&
  1705.                 (addr >= (unsigned) MACH_IO_SLOT_ADDR(5))) {
  1706.             return TRUE;
  1707.         } else if ((addr < (unsigned) MACH_IO_SLOT_ADDR(3)) &&
  1708.                 (addr >= (unsigned) MACH_IO_SLOT_ADDR(0))) {
  1709.             return TRUE;
  1710.         }
  1711.         }
  1712.     }
  1713.     return FALSE;
  1714.     } else if (addr > (unsigned)mach_KernEnd) {
  1715.     return(FALSE);
  1716.     }
  1717.     virtPage = addr >> VMMACH_PAGE_SHIFT;
  1718.     lowEntry = vmMach_KernelTLBMap[virtPage - VMMACH_VIRT_CACHED_START_PAGE];
  1719.     if (lowEntry == 0) {
  1720.     return(FALSE);
  1721.     }
  1722.     /*
  1723.      * Use the special reserved TLB entry (entry 0).
  1724.      */
  1725.     highEntry = (virtPage << VMMACH_TLB_VIRT_PAGE_SHIFT) |
  1726.                 (VMMACH_KERN_PID << VMMACH_TLB_PID_SHIFT);
  1727.     VmMachWriteIndexedTLB(0, lowEntry, highEntry);
  1728.     return(TRUE);
  1729. }
  1730.  
  1731. #define TLB_HASH(pid, page) \
  1732.     ((page) ^ ((pid) << (VMMACH_PID_HASH_SHIFT + VMMACH_TLB_PID_SHIFT - \
  1733.              VMMACH_BUCKET_SIZE_SHIFT))) & VMMACH_HASH_MASK_2
  1734.  
  1735.  
  1736. /*
  1737.  *----------------------------------------------------------------------
  1738.  *
  1739.  * TLBHashFind --
  1740.  *
  1741.  *    Find the entry with the given key in the hash table.
  1742.  *
  1743.  * Results:
  1744.  *    Pointer to hash table entry if found, NIL otherwise.
  1745.  *
  1746.  * Side effects:
  1747.  *    None.
  1748.  *
  1749.  *----------------------------------------------------------------------
  1750.  */
  1751. INTERNAL static TLBHashBucket *
  1752. TLBHashFind(pid, page)
  1753.     int        pid;
  1754.     unsigned    page;
  1755. {
  1756.     TLBHashBucket    *hashBucketPtr;
  1757.  
  1758.     tlbCountersPtr->numProbes++;
  1759.  
  1760.     hashBucketPtr = &vmMachTLBHashTable[TLB_HASH(pid, page)];
  1761.     if (hashBucketPtr->high == ((page << VMMACH_TLB_VIRT_PAGE_SHIFT) |
  1762.                 (pid << VMMACH_TLB_PID_SHIFT))) {
  1763.     tlbCountersPtr->numFound++;
  1764.     return(hashBucketPtr);
  1765.     } else {
  1766.     return((TLBHashBucket *)NIL);
  1767.     }
  1768. }
  1769.  
  1770.  
  1771. /*
  1772.  *----------------------------------------------------------------------
  1773.  *
  1774.  * TLBHashDelete --
  1775.  *
  1776.  *    Find the entry with the given key in the hash table and delete it.
  1777.  *
  1778.  * Results:
  1779.  *    None.
  1780.  *
  1781.  * Side effects:
  1782.  *    Entry may be deleted from the hash table.
  1783.  *
  1784.  *----------------------------------------------------------------------
  1785.  */
  1786. INTERNAL static void
  1787. TLBHashDelete(pid, page)
  1788.     int        pid;
  1789.     unsigned    page;
  1790. {
  1791.     TLBHashBucket    *hashBucketPtr;
  1792.  
  1793.     hashBucketPtr = &vmMachTLBHashTable[TLB_HASH(pid, page)];
  1794.     if (hashBucketPtr->high == ((page << VMMACH_TLB_VIRT_PAGE_SHIFT) |
  1795.                 (pid << VMMACH_TLB_PID_SHIFT))) {
  1796.     hashBucketPtr->high = 0;
  1797.     List_Remove((List_Links *)hashBucketPtr);
  1798.     }
  1799. }
  1800.  
  1801.  
  1802. /*
  1803.  *----------------------------------------------------------------------
  1804.  *
  1805.  * TLBHashInsert --
  1806.  *
  1807.  *    Insert the entry in the hash table if it is not already there.
  1808.  *
  1809.  * Results:
  1810.  *    None.
  1811.  *
  1812.  * Side effects:
  1813.  *    Entry may be added to the hash table.
  1814.  *
  1815.  *----------------------------------------------------------------------
  1816.  */
  1817. INTERNAL static void
  1818. TLBHashInsert(pid, page, lowReg, hiReg)
  1819.     int        pid;
  1820.     unsigned    page;
  1821.     unsigned    lowReg;
  1822.     unsigned    hiReg;
  1823. {
  1824.     TLBHashBucket    *hashBucketPtr;
  1825.  
  1826.     if (pid == VMMACH_KERN_PID) {
  1827.     /*
  1828.      * Don't insert any entries for the kernel pid.  This will only 
  1829.      * happen because a process with no VM is doing a CopyOutProc.
  1830.      */
  1831.     return;
  1832.     }
  1833.  
  1834.     tlbCountersPtr->numInserts++;
  1835.     hashBucketPtr = &vmMachTLBHashTable[TLB_HASH(pid, page)];
  1836.     if (hashBucketPtr->high == hiReg) {
  1837.     return;
  1838.     }
  1839.     if (hashBucketPtr->high != 0) {
  1840.     tlbCountersPtr->numCollisions++;
  1841.     List_Remove((List_Links *)hashBucketPtr);
  1842.     }
  1843.     hashBucketPtr->low = lowReg;
  1844.     hashBucketPtr->high = hiReg;
  1845.     List_Insert((List_Links *)hashBucketPtr,
  1846.         LIST_ATREAR(&pidListElems[pid].tlbList));
  1847. }
  1848.  
  1849.  
  1850. /*
  1851.  *----------------------------------------------------------------------
  1852.  *
  1853.  * TLBHashFlushPID --
  1854.  *
  1855.  *    Flush all entries for the given PID from the hash table.
  1856.  *
  1857.  * Results:
  1858.  *    None.
  1859.  *
  1860.  * Side effects:
  1861.  *    All entries for the given PID are flushed from the hash table.
  1862.  *
  1863.  *----------------------------------------------------------------------
  1864.  */
  1865. INTERNAL static void
  1866. TLBHashFlushPID(pid)
  1867.     int    pid;
  1868. {
  1869.     PIDListElem        *pidPtr;
  1870.     TLBHashBucket    *hashBucketPtr;
  1871.  
  1872.     pidPtr = &pidListElems[pid];
  1873.     while (!List_IsEmpty(&pidPtr->tlbList)) {
  1874.     hashBucketPtr = (TLBHashBucket *)List_First(&pidPtr->tlbList);
  1875.     List_Remove((List_Links *)hashBucketPtr);
  1876.     hashBucketPtr->high = 0;
  1877.     }
  1878. }
  1879.  
  1880.  
  1881. /*
  1882.  *----------------------------------------------------------------------
  1883.  *
  1884.  * VmMach_MakeNonCacheable --
  1885.  *
  1886.  *    Make the given page non-cacheable.
  1887.  *
  1888.  * Results:
  1889.  *    None.
  1890.  *
  1891.  * Side effects:
  1892.  *    None.
  1893.  *
  1894.  *----------------------------------------------------------------------
  1895.  */
  1896. ENTRY void
  1897. VmMach_MakeNonCacheable(procPtr, addr)
  1898.     Proc_ControlBlock    *procPtr;
  1899.     Address        addr;
  1900. {
  1901.     TLBHashBucket    *bucketPtr;
  1902.  
  1903.     MASTER_LOCK(vmMachMutexPtr);
  1904.  
  1905.     VmMachFlushTLB();
  1906.     bucketPtr = TLBHashFind(procPtr->vmPtr->machPtr->pid,
  1907.                 (unsigned)addr >> VMMACH_PAGE_SHIFT);
  1908.     if (bucketPtr != (TLBHashBucket *)NIL) {
  1909.     bucketPtr->low |= VMMACH_TLB_NON_CACHEABLE_BIT;
  1910.     } else {
  1911.     printf("VmMach_MakeNonCacheable: Not found\n");
  1912.     }
  1913.  
  1914.     MASTER_UNLOCK(vmMachMutexPtr);
  1915. }
  1916.  
  1917. static char *userMapAllocPtr = (char *) VMMACH_USER_MAPPING_BASE_ADDR;
  1918.  
  1919.  
  1920. /*
  1921.  *----------------------------------------------------------------------
  1922.  *
  1923.  * VmMach_UserMap --
  1924.  *
  1925.  *    Map the given range of kernel physical addresses into the
  1926.  *    given user's virtual address space.  This is only used for the X
  1927.  *    server and thus    there can only be one user mapping at once.
  1928.  *
  1929.  * Results:
  1930.  *    None.
  1931.  *
  1932.  * Side effects:
  1933.  *    None.
  1934.  *
  1935.  *----------------------------------------------------------------------
  1936.  */
  1937. ReturnStatus
  1938. VmMach_UserMap(numBytes, addr, physAddr,cache, newAddrPtr)
  1939.     int        numBytes;
  1940.     Address    addr;
  1941.     Address    physAddr;
  1942.     Boolean    cache;        /* Should the region be cacheable?. */
  1943.     Address    *newAddrPtr;
  1944. {
  1945.     int                i;
  1946.     Address            retAddr;
  1947.     unsigned            firstPhysPage;
  1948.     unsigned            lastPhysPage;
  1949.     VmMach_KernSharedInfo    *infoPtr;
  1950.     Proc_ControlBlock           *procPtr;
  1951.     ReturnStatus        status = SUCCESS;
  1952.     Vm_Segment              *segPtr;
  1953.     Vm_VirtAddr            virtAddr;
  1954.     Vm_PTE            *ptePtr;
  1955.     unsigned            physPage;
  1956.     Boolean            doAlloc;
  1957.  
  1958.     procPtr = Proc_GetCurrentProc();
  1959.     if (addr == (Address) NIL) {
  1960.     /* 
  1961.      * If we have to allocate the space ourselves then we allocate it
  1962.      * up above the stack in the user mapping region.  We add it to
  1963.      * the stack segment.  Note that the allocation algorithm is
  1964.      * really stupid. It assumes that only the X server is going to use
  1965.      * this allocation.
  1966.      */
  1967.     doAlloc = TRUE;
  1968.     segPtr = procPtr->vmPtr->segPtrArray[VM_HEAP];
  1969.     addr = (Address) ((unsigned) userMapAllocPtr | 
  1970.             ((unsigned) physAddr & VMMACH_OFFSET_MASK));
  1971.     if ((unsigned) userMapAllocPtr > (unsigned)
  1972.         (VMMACH_USER_MAPPING_BASE_ADDR + 
  1973.         VMMACH_USER_MAPPING_PAGES * vm_PageSize)) {
  1974.         printf("Out of mapping pages.\n");
  1975.         return FAILURE;
  1976.     }
  1977.     } else {
  1978.     doAlloc = FALSE;
  1979.     segPtr = procPtr->vmPtr->segPtrArray[VM_HEAP];
  1980.     }
  1981.     infoPtr = (VmMach_KernSharedInfo *) malloc(sizeof(VmMach_KernSharedInfo));
  1982.     bzero((char *) infoPtr, sizeof(*infoPtr));
  1983.     List_InitElement((List_Links *) infoPtr);
  1984.     firstPhysPage = (unsigned)physAddr >> VMMACH_PAGE_SHIFT;
  1985.     lastPhysPage = (unsigned)(physAddr + numBytes - 1) >> VMMACH_PAGE_SHIFT;
  1986.     infoPtr->firstPage = (unsigned) addr >> VMMACH_PAGE_SHIFT;
  1987.     infoPtr->lastPage = 
  1988.     (unsigned)(addr + numBytes - 1) >> VMMACH_PAGE_SHIFT;
  1989.     if (!cache) {
  1990.     infoPtr->flags |= VMMACH_KERN_SHARED_UNCACHEABLE;
  1991.     }
  1992.     if (!doAlloc) {
  1993.     status = Vm_DeleteFromSeg(segPtr, infoPtr->firstPage, 
  1994.             infoPtr->lastPage);
  1995.     if (status != SUCCESS) {
  1996.         printf("VmMach_UserMap: Vm_DeleteFromSeg failed 0x%x\n", status);
  1997.         free((char *) infoPtr);
  1998.         return status;
  1999.     }
  2000.     status = VmAddToSeg(segPtr, infoPtr->firstPage, infoPtr->lastPage);
  2001.     if (status != SUCCESS) {
  2002.         printf("VmMach_UserMap: VmAddToSeg failed 0x%x\n", status);
  2003.         free((char *) infoPtr);
  2004.         return status;
  2005.     }
  2006.     virtAddr.segPtr = segPtr;
  2007.     virtAddr.sharedPtr = (Vm_SegProcList *)NIL;
  2008.     for(virtAddr.page = infoPtr->firstPage, 
  2009.         physPage = firstPhysPage,
  2010.         ptePtr = VmGetPTEPtr(segPtr, infoPtr->firstPage);
  2011.         virtAddr.page <= infoPtr->lastPage;
  2012.         virtAddr.page++, physPage++, VmIncPTEPtr(ptePtr, 1)) {
  2013.     
  2014.         *ptePtr |= VM_PHYS_RES_BIT | VM_REFERENCED_BIT;
  2015.         *ptePtr |= (physPage & VM_PAGE_FRAME_FIELD);
  2016.     }
  2017.     infoPtr->firstPhysPage = (unsigned) NIL;
  2018.     } else {
  2019.     userMapAllocPtr += (infoPtr->lastPage - infoPtr->firstPage + 1) * 
  2020.                 vm_PageSize;
  2021.     infoPtr->firstPhysPage = firstPhysPage;
  2022.     }
  2023.     List_Insert((List_Links *) infoPtr, 
  2024.     LIST_ATFRONT(&procPtr->vmPtr->machPtr->kernSharedList));
  2025.     /*
  2026.      * Make sure this process never migrates.
  2027.      */
  2028.     Proc_NeverMigrate(procPtr);
  2029.     *newAddrPtr = addr;
  2030.     return status;
  2031. }
  2032.  
  2033.  
  2034. /*
  2035.  *----------------------------------------------------------------------
  2036.  *
  2037.  * VmMach_UserUnmap --
  2038.  *
  2039.  *    Unmap all pages mapped into a user's address space.
  2040.  *
  2041.  * Results:
  2042.  *    None.
  2043.  *
  2044.  * Side effects:
  2045.  *    None.
  2046.  *
  2047.  *----------------------------------------------------------------------
  2048.  */
  2049. ENTRY ReturnStatus
  2050. VmMach_UserUnmap(addr)
  2051.     Address        addr;
  2052. {
  2053.     int                pid;
  2054.     Proc_ControlBlock        *procPtr;
  2055.     List_Links            *listPtr;
  2056.     VmMach_KernSharedInfo    *infoPtr;
  2057.     List_Links            *tmpPtr;
  2058.     int                page;
  2059.     Boolean            doAll = FALSE;
  2060.     ReturnStatus        status = SUCCESS;
  2061.     Vm_Segment              *segPtr;
  2062.     Vm_PTE            *ptePtr;
  2063.  
  2064.     procPtr = Proc_GetCurrentProc();
  2065.     pid = procPtr->vmPtr->machPtr->pid;
  2066.     if (addr == (Address) NIL) {
  2067.     doAll = TRUE;
  2068.     }
  2069.     page = (unsigned) addr >> VMMACH_PAGE_SHIFT;
  2070.     tmpPtr = (List_Links *) NIL;
  2071.     listPtr = &procPtr->vmPtr->machPtr->kernSharedList;
  2072.     LIST_FORALL(listPtr, (List_Links *) infoPtr) {
  2073.     if (doAll) {
  2074.         if (tmpPtr != (List_Links *) NIL) {
  2075.         List_Remove(tmpPtr);
  2076.         free((char *) tmpPtr);
  2077.         }
  2078.     }
  2079.     if (doAll || infoPtr->firstPage == page) {
  2080.         if (infoPtr->firstPage < VMMACH_USER_MAPPING_BASE_PAGE) {
  2081.         segPtr = procPtr->vmPtr->segPtrArray[VM_HEAP];
  2082.         for(ptePtr = VmGetPTEPtr(segPtr, infoPtr->firstPage);
  2083.             page <= infoPtr->lastPage;
  2084.             page++, VmIncPTEPtr(ptePtr, 1)) {
  2085.  
  2086.             *ptePtr = 0;
  2087.         }
  2088.         } else {
  2089.         userMapAllocPtr = (char *) VMMACH_USER_MAPPING_BASE_ADDR;
  2090.         }
  2091.         tmpPtr = (List_Links *) infoPtr;
  2092.         if (!doAll) {
  2093.         break;
  2094.         }
  2095.     }
  2096.     }
  2097.     if (tmpPtr != (List_Links *) NIL) {
  2098.     List_Remove(tmpPtr);
  2099.     free((char *) tmpPtr);
  2100.     } else if (!doAll) {
  2101.     return FAILURE;
  2102.     }
  2103.     if (pid != VMMACH_INV_PID && pid != VMMACH_KERN_PID) {
  2104.     MASTER_LOCK(vmMachMutexPtr);
  2105.     TLBHashFlushPID(pid);
  2106.     MASTER_UNLOCK(vmMachMutexPtr);
  2107.     }
  2108.     return SUCCESS;
  2109. }
  2110.  
  2111.  
  2112. #define ALLOC(x,s)    (sharedData->allocVector[(x)]=s)
  2113. #define FREE(x)        (sharedData->allocVector[(x)]=0)
  2114. #define SIZE(x)        (sharedData->allocVector[(x)])
  2115. #define ISFREE(x)    (sharedData->allocVector[(x)]==0)
  2116.  
  2117.  
  2118.  
  2119. /*
  2120.  * ----------------------------------------------------------------------------
  2121.  *
  2122.  * VmMach_Alloc --
  2123.  *
  2124.  *      Allocates a region of shared memory;
  2125.  *
  2126.  * Results:
  2127.  *      SUCCESS if the region can be allocated.
  2128.  *    The starting address is returned in addr.
  2129.  *
  2130.  * Side effects:
  2131.  *      The allocation vector is updated.
  2132.  *
  2133.  * ----------------------------------------------------------------------------
  2134.  */
  2135. static ReturnStatus
  2136. VmMach_Alloc(sharedData, regionSize, addr)
  2137.     VmMach_SharedData    *sharedData;    /* Pointer to shared memory info.  */
  2138.     int            regionSize;    /* Size of region to allocate. */
  2139.     Address        *addr;        /* Address of region. */
  2140. {
  2141.     int numBlocks = (regionSize+VMMACH_SHARED_BLOCK_SIZE-1) /
  2142.         VMMACH_SHARED_BLOCK_SIZE;
  2143.     int i, blockCount, firstBlock;
  2144.  
  2145.     if (sharedData->allocVector == (int *)NULL || sharedData->allocVector ==
  2146.         (int *)NIL) {
  2147.     dprintf("VmMach_Alloc: allocVector uninitialized!\n");
  2148.     }
  2149.  
  2150.     /*
  2151.      * Loop through the alloc vector until we find numBlocks free blocks
  2152.      * consecutively.
  2153.      */
  2154.     blockCount = 0;
  2155.     for (i=sharedData->allocFirstFree;
  2156.         i<=VMMACH_SHARED_NUM_BLOCKS-1 && blockCount<numBlocks;i++) {
  2157.     if (ISFREE(i)) {
  2158.         blockCount++;
  2159.     } else {
  2160.         blockCount = 0;
  2161.         if (i==sharedData->allocFirstFree) {
  2162.         sharedData->allocFirstFree++;
  2163.         }
  2164.     }
  2165.     }
  2166.     if (blockCount < numBlocks) {
  2167.     dprintf("VmMach_Alloc: got %d blocks of %d of %d total\n",
  2168.         blockCount,numBlocks,VMMACH_SHARED_NUM_BLOCKS);
  2169.     return VM_NO_SEGMENTS;
  2170.     }
  2171.     firstBlock = i-blockCount;
  2172.     if (firstBlock == sharedData->allocFirstFree) {
  2173.     sharedData->allocFirstFree += blockCount;
  2174.     }
  2175.     *addr = (Address)(firstBlock*VMMACH_SHARED_BLOCK_SIZE +
  2176.         VMMACH_SHARED_START_ADDR);
  2177.     for (i = firstBlock; i<firstBlock+numBlocks; i++) {
  2178.     ALLOC(i,numBlocks);
  2179.     }
  2180.     dprintf("VmMach_Alloc: got %d blocks at %d (%x)\n",
  2181.         numBlocks,firstBlock,*addr);
  2182.     return SUCCESS;
  2183. }
  2184.  
  2185.  
  2186. /*
  2187.  * ----------------------------------------------------------------------------
  2188.  *
  2189.  * VmMach_Unalloc --
  2190.  *
  2191.  *      Frees a region of shared address space.
  2192.  *
  2193.  * Results:
  2194.  *      None.
  2195.  *
  2196.  * Side effects:
  2197.  *      The allocation vector is updated.
  2198.  *
  2199.  * ----------------------------------------------------------------------------
  2200.  */
  2201.  
  2202. static void
  2203. VmMach_Unalloc(sharedData, addr)
  2204.     VmMach_SharedData    *sharedData;    /* Pointer to shared memory info. */
  2205.     Address    addr;        /* Address of region. */
  2206. {
  2207.     int firstBlock = ((int)addr-VMMACH_SHARED_START_ADDR) /
  2208.         VMMACH_SHARED_BLOCK_SIZE;
  2209.     int numBlocks = SIZE(firstBlock);
  2210.     int i;
  2211.  
  2212.     dprintf("VmMach_Unalloc: freeing %d blocks at %x\n",numBlocks,addr);
  2213.     if (firstBlock < sharedData->allocFirstFree) {
  2214.     sharedData->allocFirstFree = firstBlock;
  2215.     }
  2216.     for (i=0;i<numBlocks;i++) {
  2217.     if (ISFREE(i+firstBlock)) {
  2218.         printf("Freeing free shared address %d %d %d\n",i,i+firstBlock,
  2219.             (int)addr);
  2220.         return;
  2221.     }
  2222.     FREE(i+firstBlock);
  2223.     }
  2224. }
  2225.  
  2226. /*
  2227.  * ----------------------------------------------------------------------------
  2228.  *
  2229.  * VmMach_SharedStartAddr --
  2230.  *
  2231.  *      Determine the starting address for a shared segment.
  2232.  *
  2233.  * Results:
  2234.  *      Returns the proper start address for the segment.
  2235.  *
  2236.  * Side effects:
  2237.  *      Allocates part of the shared address space.
  2238.  *
  2239.  * ----------------------------------------------------------------------------
  2240.  */
  2241. ReturnStatus
  2242. VmMach_SharedStartAddr(procPtr,size,reqAddr, fixed)
  2243.     Proc_ControlBlock   *procPtr;
  2244.     int             size;           /* Length of shared segment. */
  2245.     Address         *reqAddr;        /* Requested start address. */
  2246.     int             fixed;          /* 1 if fixed address requested. */
  2247. {
  2248.     int numBlocks = (size+VMMACH_SHARED_BLOCK_SIZE-1) /
  2249.             VMMACH_SHARED_BLOCK_SIZE;
  2250.     int firstBlock = (((int)*reqAddr)-VMMACH_SHARED_START_ADDR+
  2251.             VMMACH_SHARED_BLOCK_SIZE-1) /
  2252.             VMMACH_SHARED_BLOCK_SIZE;
  2253.     int i;
  2254.     VmMach_SharedData   *sharedData = &procPtr->vmPtr->machPtr->sharedData;
  2255.  
  2256.     if (fixed==0) {
  2257.         return VmMach_Alloc(sharedData, size, reqAddr);
  2258.     } else {
  2259.         for (i = firstBlock; i<firstBlock+numBlocks; i++) {
  2260.             if (i>0) {
  2261.                 ALLOC(i,numBlocks);
  2262.             }
  2263.         }
  2264.         return SUCCESS;
  2265.     }
  2266. }
  2267.  
  2268. /*
  2269.  * ----------------------------------------------------------------------------
  2270.  *
  2271.  * VmMach_SharedProcStart --
  2272.  *
  2273.  *      Perform machine dependent initialization of shared memory
  2274.  *    for this process.
  2275.  *
  2276.  * Results:
  2277.  *      None.
  2278.  *
  2279.  * Side effects:
  2280.  *      The storage allocation structures are initialized.
  2281.  *
  2282.  * ----------------------------------------------------------------------------
  2283.  */
  2284. void
  2285. VmMach_SharedProcStart(procPtr)
  2286.     Proc_ControlBlock    *procPtr;
  2287. {
  2288.     VmMach_SharedData    *sharedData = &procPtr->vmPtr->machPtr->sharedData;
  2289.     dprintf("VmMach_SharedProcStart: initializing proc's allocVector\n");
  2290.     if (sharedData->allocVector != (int *)NIL) {
  2291.     panic("VmMach_SharedProcStart: allocVector not NIL\n");
  2292.     }
  2293.     sharedData->allocVector =
  2294.         (int *)malloc(VMMACH_SHARED_NUM_BLOCKS*sizeof(int));
  2295.     sharedData->allocFirstFree = 0;
  2296.     bzero((Address) sharedData->allocVector, VMMACH_SHARED_NUM_BLOCKS*
  2297.         sizeof(int));
  2298.     procPtr->vmPtr->sharedStart = (Address) VMMACH_SHARED_START_ADDR;
  2299.     procPtr->vmPtr->sharedEnd = (Address) VMMACH_SHARED_START_ADDR+
  2300.         VMMACH_USER_SHARED_PAGES*VMMACH_PAGE_SIZE;
  2301. }
  2302.  
  2303. /*
  2304.  * ----------------------------------------------------------------------------
  2305.  *
  2306.  * VmMach_SharedSegFinish --
  2307.  *
  2308.  *      Perform machine dependent cleanup of shared memory
  2309.  *    for this segment.
  2310.  *
  2311.  * Results:
  2312.  *      None.
  2313.  *
  2314.  * Side effects:
  2315.  *      The storage allocation structures are freed.
  2316.  *
  2317.  * ----------------------------------------------------------------------------
  2318.  */
  2319. void
  2320. VmMach_SharedSegFinish(procPtr,addr)
  2321.     Proc_ControlBlock    *procPtr;
  2322.     Address        addr;
  2323. {
  2324.     VmMach_Unalloc(&procPtr->vmPtr->machPtr->sharedData,addr);
  2325. }
  2326.  
  2327. /*
  2328.  * ----------------------------------------------------------------------------
  2329.  *
  2330.  * VmMach_SharedProcFinish --
  2331.  *
  2332.  *      Perform machine dependent cleanup of shared memory
  2333.  *    for this process.
  2334.  *
  2335.  * Results:
  2336.  *      None.
  2337.  *
  2338.  * Side effects:
  2339.  *      The storage allocation structures are freed.
  2340.  *
  2341.  * ----------------------------------------------------------------------------
  2342.  */
  2343. void
  2344. VmMach_SharedProcFinish(procPtr)
  2345.     Proc_ControlBlock    *procPtr;
  2346. {
  2347.     dprintf("VmMach_SharedProcFinish: freeing process's allocVector\n");
  2348.     free((Address)procPtr->vmPtr->machPtr->sharedData.allocVector);
  2349.     procPtr->vmPtr->machPtr->sharedData.allocVector;
  2350.     procPtr->vmPtr->machPtr->sharedData.allocVector = (int *)NIL;
  2351. }
  2352.  
  2353. /*
  2354.  * ----------------------------------------------------------------------------
  2355.  *
  2356.  * VmMach_CopySharedMem --
  2357.  *
  2358.  *      Copies machine-dependent shared memory data structures to handle
  2359.  *    a fork.
  2360.  *
  2361.  * Results:
  2362.  *      None.
  2363.  *
  2364.  * Side effects:
  2365.  *      The new process gets a copy of the shared memory structures.
  2366.  *
  2367.  * ----------------------------------------------------------------------------
  2368.  */
  2369. void
  2370. VmMach_CopySharedMem(parentProcPtr, childProcPtr)
  2371.     Proc_ControlBlock   *parentProcPtr; /* Parent process. */
  2372.     Proc_ControlBlock   *childProcPtr;  /* Child process. */
  2373. {
  2374.     VmMach_SharedData    *childSharedData =
  2375.         &childProcPtr->vmPtr->machPtr->sharedData;
  2376.     VmMach_SharedData    *parentSharedData =
  2377.         &parentProcPtr->vmPtr->machPtr->sharedData;
  2378.  
  2379.     VmMach_SharedProcStart(childProcPtr);
  2380.  
  2381.     bcopy(parentSharedData->allocVector, childSharedData->allocVector,
  2382.         VMMACH_SHARED_NUM_BLOCKS*sizeof(int));
  2383.     childSharedData->allocFirstFree = parentSharedData->allocFirstFree;
  2384. }
  2385.  
  2386. /*
  2387.  * ----------------------------------------------------------------------------
  2388.  *
  2389.  * VmMach_LockCachePage --
  2390.  *
  2391.  *      Perform machine dependent locking of a kernel resident file cache
  2392.  *    page.
  2393.  *
  2394.  * Results:
  2395.  *      None.
  2396.  *
  2397.  * Side effects:
  2398.  *
  2399.  * ----------------------------------------------------------------------------
  2400.  */
  2401. void
  2402. VmMach_LockCachePage(kernelAddress)
  2403.     Address    kernelAddress;    /* Address on page to lock. */
  2404. {
  2405.     /*
  2406.      * Ds3100 leaves file cache pages always available so there is no need to
  2407.      * lock or unlock them.
  2408.      */
  2409.     return;
  2410. }
  2411.  
  2412. /*
  2413.  * ----------------------------------------------------------------------------
  2414.  *
  2415.  * VmMach_UnlockCachePage --
  2416.  *
  2417.  *      Perform machine dependent unlocking of a kernel resident page.
  2418.  *
  2419.  * Results:
  2420.  *      None.
  2421.  *
  2422.  * Side effects:
  2423.  *
  2424.  * ----------------------------------------------------------------------------
  2425.  */
  2426. void
  2427. VmMach_UnlockCachePage(kernelAddress)
  2428.     Address    kernelAddress;    /* Address on page to unlock. */
  2429. {
  2430.     /*
  2431.      * Ds3100 leaves file cache pages always available so there is no need to
  2432.      * lock or unlock them.
  2433.      */
  2434.     return;
  2435. }
  2436.  
  2437.